home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
biz
/
ccard11
/
ccard.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-28
|
6KB
|
255 lines
/*
* ccard - credit card number validation
* 1994 Peter Miller
* Public Domain
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* MANIFEST: functions to validate credit card numbers
*
* derived from code by
* Chris Stone <cstone@hms.com>
* The High Mountain Software Internet Gateway
*
* translated to C by
* Peter Miller, 28-Oct-94
* This source is hereby placed in the Public Domain.
* Please leave my name on it,
* and document changes in this header block.
*
* NO WARRANTY
*
* BECAUSE THE PROGRAM IS IN THE PUBLIC DOMAIN, THERE IS NO
* WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
* LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE AUTHORS
* AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
* WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
* THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD
* THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
* NECESSARY SERVICING, REPAIR OR CORRECTION.
*
* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
* WRITING WILL ANY AUTHOR, OR ANY OTHER PARTY WHO MAY MODIFY
* AND/OR REDISTRIBUTE THE PROGRAM, BE LIABLE TO YOU FOR DAMAGES,
* INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
* DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
* (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
* RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
* OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
* PROGRAMS), EVEN IF SUCH AUTHOR OR OTHER PARTY HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <ctype.h>
#include <ac/string.h>
#include <ccard.h>
#define SIZEOF(a) (sizeof(a) / sizeof((a)[0]))
#define ENDOF(a) ((a) + SIZEOF(a))
#define MINLEN 12
#define MAXLEN (MINLEN + 16)
#define L(n) (1 << ((n) - MINLEN))
char *
ccard_type_name(n)
ccard_type_ty n;
{
static char *name[] =
{
"unknown",
"Mastercard",
"Visa",
"American Express",
"Diners Club/Carte Blanche",
"Discover",
"enRoute",
"Japanese Credit Bureau",
"Australian Bankcard",
};
if (n < 0 || n >= SIZEOF(name))
n = 0;
return name[n];
}
char *
ccard_error_name(n)
ccard_error_ty n;
{
static char *name[] =
{
"no error",
"card type unknown",
"card number contains non numeric characters",
"card number is far too long",
"card number is the wrong length",
"checksum incorrect",
};
if (n < 0 || n >= SIZEOF(name))
return "unknown";
return name[n];
}
static int verify_checksum _((char *));
static int
verify_checksum(credit_card)
char *credit_card;
{
char *cp;
int dbl;
int check_sum;
/*
* This checksum algorithm has a name,
* but I can't think of it.
*/
check_sum = 0;
dbl = 0;
/* assert(credit_card[0]); */
cp = credit_card + strlen(credit_card) - 1;
while (cp >= credit_card)
{
int c;
c = *cp-- - '0';
if (dbl)
{
c *= 2;
if (c >= 10)
c -= 9;
}
check_sum += c;
dbl = !dbl;
}
return ((check_sum % 10) == 0);
}
static int all_numeric _((char *, char *, int));
static int
all_numeric(s1, s2, max)
char *s1;
char *s2;
int max;
{
while (*s1)
{
if (isspace(*s1) || *s1 == '-')
{
++s1;
continue;
}
if (!isdigit(*s1))
return ccard_error_non_numeric;
if (max <= 0)
return ccard_error_too_long;
*s2++ = *s1++;
--max;
}
*s2 = 0;
return ccard_error_none;
}
ccard_error_ty
ccard_valid(credit_card_in, card_type)
char *credit_card_in;
ccard_type_ty *card_type;
{
typedef struct table_ty table_ty;
struct table_ty
{
char *prefix;
int length_mask;
ccard_type_ty type;
int checksum;
};
static table_ty table[] =
{
{ "1800", L(15), ccard_type_jcb, 1, },
{ "2014", L(15), ccard_type_enroute, 0, },
{ "2131", L(15), ccard_type_jcb, 1, },
{ "2149", L(15), ccard_type_enroute, 0, },
{ "300", L(14), ccard_type_diners, 1, },
{ "301", L(14), ccard_type_diners, 1, },
{ "302", L(14), ccard_type_diners, 1, },
{ "303", L(14), ccard_type_diners, 1, },
{ "304", L(14), ccard_type_diners, 1, },
{ "305", L(14), ccard_type_diners, 1, },
{ "34", L(15), ccard_type_amex, 1, },
{ "36", L(14), ccard_type_diners, 1, },
{ "37", L(15), ccard_type_amex, 1, },
{ "38", L(14), ccard_type_diners, 1, },
{ "3", L(16), ccard_type_jcb, 1, },
{ "4", L(13)|L(16), ccard_type_visa, 1, },
{ "51", L(16), ccard_type_mastercard, 1, },
{ "52", L(16), ccard_type_mastercard, 1, },
{ "53", L(16), ccard_type_mastercard, 1, },
{ "54", L(16), ccard_type_mastercard, 1, },
{ "55", L(16), ccard_type_mastercard, 1, },
{ "56", L(16), ccard_type_bankcard, 1, },
{ "6011", L(16), ccard_type_discover, 1, },
};
table_ty *tp;
char credit_card[MAXLEN + 1];
ccard_error_ty err;
int len;
/*
* copy the number, eliding spaces
* defer any errors until after we have tried to guess the card type
*/
err = all_numeric(credit_card_in, credit_card, MAXLEN);
/*
* look for the card prefix in the table
* to determine the card type
*/
for (tp = table; tp < ENDOF(table); ++tp)
{
if (!memcmp(tp->prefix, credit_card, strlen(tp->prefix)))
break;
}
if (tp >= ENDOF(table))
{
*card_type = ccard_type_unknown;
return ccard_error_type_unknown;
}
*card_type = tp->type;
if (err != ccard_error_none)
return err;
/*
* set the card type, then check the length
*/
/* assert(tp->correct_length <= MAXLEN); */
len = strlen(credit_card);
if (len < MINLEN || (L(len) & tp->length_mask) == 0)
return ccard_error_length_incorrect;
/*
* checksum
*/
if (tp->checksum && !verify_checksum(credit_card))
return ccard_error_checksum;
/*
* no errors found
*/
return ccard_error_none;
}